package com.ts.api.module.channel.service.impl;

import com.gitee.apanlh.util.base.CollUtils;
import com.gitee.apanlh.util.base.Eq;
import com.gitee.apanlh.util.base.IteratorUtils;
import com.gitee.apanlh.util.valid.ValidParam;
import com.ts.api.common.constant.BizEnum;
import com.ts.api.common.context.ChannelContext;
import com.ts.api.common.context.ChannelRequestContext;
import com.ts.api.common.context.ChannelUserContext;
import com.ts.api.exp.BizException;
import com.ts.api.module.channel.dao.ChannelFormDao;
import com.ts.api.module.channel.entity.po.ChannelFormFieldPO;
import com.ts.api.module.channel.entity.po.ChannelUserFormFieldPO;
import com.ts.api.module.channel.entity.po.ChannelUserFormPO;
import com.ts.api.module.channel.entity.qo.ChannelUserFormMappingQO;
import com.ts.api.module.channel.entity.vo.ReqChannelFormVO;
import com.ts.api.module.channel.service.ChannelFormService;
import com.ts.cache.form.FormCacheService;
import com.ts.cache.form.entity.FormCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Set;

@Service
public class ChannelFormServiceImpl implements ChannelFormService {

    @Autowired
    private ChannelFormDao formFieldDao;
    @Autowired
    private FormCacheService formCacheService;

    @Override
    @Transactional(readOnly = true)
    public List<ChannelFormFieldPO> listByChannelId(Long channelId) {
        List<ChannelFormFieldPO> list = formFieldDao.listByChannelId(channelId);

        String getTableFlow = ChannelRequestContext.getTableFlow();
        String[] mappingName = new String[] {"sesameCredit", "realEstateInfo", "carInfo", "providentFund", "socialSecurity", "overdue"};

        //  前置表单
        if ("1".equals(getTableFlow)) {
            //  过滤表单
            CollUtils.filter(list, t -> {
                if (Eq.str("realEstateInfo", t.getMappingName())) {
                    return !Eq.str("4", t.getMappingValue());
                }
                if (Eq.str("carInfo", t.getMappingName())) {
                    return !Eq.str("4", t.getMappingValue());
                }
                if (Eq.str("providentFund", t.getMappingName())) {
                    return !Eq.str("4", t.getMappingValue());
                }
                if (Eq.str("socialSecurity", t.getMappingName())) {
                    return !Eq.str("4", t.getMappingValue());
                }
                return !Eq.strOr(t.getMappingName(), mappingName);
            });
        }
        //  中置表单
        if ("2".equals(getTableFlow)) {
            CollUtils.filter(list, t -> Eq.strOr(t.getMappingName(), mappingName));
        }
        return list;
    }

    @Override
    @Transactional(readOnly = true)
    public List<ChannelUserFormFieldPO> listUserFormField() {
        return formFieldDao.listUserFormField(ChannelUserContext.getId());
    }

    @Override
    @Transactional(readOnly = true)
    public List<ChannelUserFormFieldPO> listUserFormField(Long userId) {
        return formFieldDao.listUserFormField(userId);
    }

    @Override
    @Transactional(readOnly = true)
    public List<ChannelUserFormFieldPO> listFieldByMappingNameAndUser(ChannelUserFormMappingQO channelUserFormMappingQO) {
        return formFieldDao.listFieldByMappingNameAndUser(channelUserFormMappingQO);
    }

    @Override
    @Transactional(readOnly = true)
    public void checkFormParam(List<ReqChannelFormVO> listVO) {
        if (ValidParam.isEmpty(listVO)) {
            BizException.fastFail(BizEnum.FORM_EMPTY);
        }
        List<ChannelFormFieldPO> listFormField = formFieldDao.listByChannelId(ChannelContext.getId());
        if (ValidParam.isEmpty(listVO)) {
            BizException.fastFail(BizEnum.FORM_EMPTY);
        }

        Set<Long> dbIds = CollUtils.distinctToSet(listFormField, t -> t.getId());
        Set<Long> dbValueIds = CollUtils.distinctToSet(listFormField, t -> t.getFieldValueId());

        List<Long> ids =  CollUtils.toList(listVO, t -> t.getFieldId());
        List<Long> valueIds = CollUtils.toList(listVO, t -> t.getFieldValueId());

        //  一个表单一个表单值id
        if (ids.size() != valueIds.size()) {
//            log.info("表单集合长度与表单值集合不一致", ChannelContext.get().getName(), ChannelContext.get().getLink());
            BizException.fastFail(BizEnum.FORM_PARAM_ID);
        }

        //  传递的表单id不包含数据库中的值
        IteratorUtils.array(ids, id -> {
            if (!dbIds.contains(id)) {
                BizException.fastFail(BizEnum.FORM_PARAM_ID2);
            }
        });
        //  传递的值不包含数据库中的值
        IteratorUtils.array(valueIds, id -> {
            if (!dbValueIds.contains(id)) {
                BizException.fastFail(BizEnum.FORM_PARAM_ID3);
            }
        });

        //  验证表单中的id是否符合表单值的id
        Map<Long, List<ChannelFormFieldPO>> groupId = CollUtils.groupBy(listFormField, t -> t.getId());
        for (int i = 0; i < ids.size(); i++) {
            Long id = ids.get(i);
            List<ChannelFormFieldPO> listGroup = groupId.get(id);

            Long valueId = valueIds.get(i);
            int indexOf = CollUtils.indexOf(listGroup, t -> Eq.object(t.getFieldValueId(), valueId));
            if (indexOf == -1) {
                BizException.fastFail(BizEnum.FORM_PARAM_ID4);
            }
        }
    }

    @Override
    public FormCache getFormMappingValue(String mappingName, String mappingValue) {
        List<FormCache> formCaches = formCacheService.get();

        FormCache findCache = CollUtils.findOne(formCaches, cacheForm -> {
            String cacheMappingName = cacheForm.getMappingName();
            if (!Eq.str(mappingName, cacheMappingName)) {
                return false;
            }
            String cacheMappingValue = cacheForm.getMappingValue();
            if (!Eq.str(mappingValue, cacheMappingValue)) {
                return false;
            }
            return true;
        });
        return findCache;
    }

    @Override
    public int batchInsertUserForm(List<ChannelUserFormPO> listChannelUserFormPO) {
        return formFieldDao.batchInsertUserForm(listChannelUserFormPO);
    }
}
